#!/bin/bash

# Thingsboard备份还原方案安装脚本
# 此脚本将安装所有必要的备份还原脚本并设置定时任务

# 检查是否以root用户运行
if [ "$(id -u)" != "0" ]; then
   echo "此脚本必须以root用户身份运行" 
   exit 1
fi

echo "开始安装Thingsboard备份还原方案..."

# 创建备份目录
BACKUP_DIR="/backup/thingsboard"
SCRIPTS_DIR="/opt/tb-backup"
LOG_DIR="/var/log"

mkdir -p ${BACKUP_DIR}
mkdir -p ${SCRIPTS_DIR}

# 创建tb_backup.sh
cat > ${SCRIPTS_DIR}/tb_backup.sh << 'EOF'
#!/bin/bash

# 备份日期格式
DATE=$(date +"%Y-%m-%d_%H-%M-%S")
BACKUP_DIR="/backup/thingsboard/${DATE}"
LOG_FILE="/var/log/tb_backup.log"

# 创建备份目录
mkdir -p ${BACKUP_DIR}

echo "开始ThingsBoard备份 - ${DATE}" | tee -a ${LOG_FILE}

# 1. 备份ThingsBoard配置
echo "备份ThingsBoard配置..." | tee -a ${LOG_FILE}
tar -czf ${BACKUP_DIR}/tb_config.tar.gz /etc/thingsboard
if [ $? -eq 0 ]; then echo "ThingsBoard配置备份成功" | tee -a ${LOG_FILE}; else echo "ThingsBoard配置备份失败" | tee -a ${LOG_FILE}; fi

# 2. 备份ThingsBoard数据目录
echo "备份ThingsBoard数据..." | tee -a ${LOG_FILE}
tar -czf ${BACKUP_DIR}/tb_data.tar.gz /var/lib/thingsboard
if [ $? -eq 0 ]; then echo "ThingsBoard数据备份成功" | tee -a ${LOG_FILE}; else echo "ThingsBoard数据备份失败" | tee -a ${LOG_FILE}; fi

# 3. 备份PostgreSQL数据库
echo "备份PostgreSQL数据库..." | tee -a ${LOG_FILE}
sudo -u postgres pg_dump thingsboard > ${BACKUP_DIR}/tb_postgres.sql
if [ $? -eq 0 ]; then echo "PostgreSQL备份成功" | tee -a ${LOG_FILE}; else echo "PostgreSQL备份失败" | tee -a ${LOG_FILE}; fi

# 4. 备份Cassandra数据库
echo "备份Cassandra数据库..." | tee -a ${LOG_FILE}

# 4.1 创建Cassandra快照
nodetool snapshot thingsboard -t tb_backup_${DATE}
if [ $? -eq 0 ]; then echo "Cassandra快照创建成功" | tee -a ${LOG_FILE}; else echo "Cassandra快照创建失败" | tee -a ${LOG_FILE}; fi

# 4.2 查找快照目录
CASSANDRA_DATA_DIR=$(grep -r "data_file_directories" /etc/cassandra/cassandra.yaml | awk '{print $2}' | tr -d '[]" ')
if [ -z "$CASSANDRA_DATA_DIR" ]; then
    CASSANDRA_DATA_DIR="/var/lib/cassandra/data"
fi

# 4.3 复制快照到备份目录
mkdir -p ${BACKUP_DIR}/cassandra
find ${CASSANDRA_DATA_DIR}/thingsboard -name "tb_backup_${DATE}" -type d -exec cp -r {} ${BACKUP_DIR}/cassandra/ \;
if [ $? -eq 0 ]; then echo "Cassandra快照复制成功" | tee -a ${LOG_FILE}; else echo "Cassandra快照复制失败" | tee -a ${LOG_FILE}; fi

# 4.4 清理Cassandra快照
nodetool clearsnapshot thingsboard -t tb_backup_${DATE}
if [ $? -eq 0 ]; then echo "Cassandra快照清理成功" | tee -a ${LOG_FILE}; else echo "Cassandra快照清理失败" | tee -a ${LOG_FILE}; fi

# 5. 备份元数据信息
echo "备份系统信息..." | tee -a ${LOG_FILE}
dpkg -l | grep -E 'thingsboard|postgresql|cassandra' > ${BACKUP_DIR}/package_versions.txt
uname -a > ${BACKUP_DIR}/system_info.txt
java -version > ${BACKUP_DIR}/java_version.txt 2>&1
echo "系统信息备份完成" | tee -a ${LOG_FILE}

# 6. 压缩整个备份目录
echo "压缩备份文件..." | tee -a ${LOG_FILE}
cd /backup/thingsboard/
tar -czf thingsboard_backup_${DATE}.tar.gz ${DATE}/
if [ $? -eq 0 ]; then 
    echo "备份文件压缩成功" | tee -a ${LOG_FILE}
    # 可选：移除原始备份文件夹以节省空间
    rm -rf ${DATE}/
else 
    echo "备份文件压缩失败" | tee -a ${LOG_FILE}
fi

# 7. 清理旧备份（保留30天）
find /backup/thingsboard/ -name "thingsboard_backup_*" -type f -mtime +30 -delete
echo "旧备份清理完成" | tee -a ${LOG_FILE}

echo "ThingsBoard备份完成 - ${DATE}" | tee -a ${LOG_FILE}
EOF

# 创建tb_verify_backup.sh
cat > ${SCRIPTS_DIR}/tb_verify_backup.sh << 'EOF'
#!/bin/bash

LATEST_BACKUP=$(find /backup/thingsboard/ -name "thingsboard_backup_*" -type f -printf "%T@ %p\n" | sort -n | tail -1 | cut -d' ' -f2-)
LOG_FILE="/var/log/tb_backup_verify.log"

if [ -z "$LATEST_BACKUP" ]; then
    echo "未找到备份文件" | tee -a ${LOG_FILE}
    exit 1
fi

echo "验证备份文件: ${LATEST_BACKUP}" | tee -a ${LOG_FILE}

# 创建临时目录
TEMP_DIR=$(mktemp -d)
tar -xzf ${LATEST_BACKUP} -C ${TEMP_DIR}

# 验证备份文件完整性
BACKUP_DATE=$(basename ${LATEST_BACKUP} | sed 's/thingsboard_backup_//' | sed 's/.tar.gz//')
EXTRACT_DIR="${TEMP_DIR}/${BACKUP_DATE}"

# 检查关键文件是否存在
if [ -f "${EXTRACT_DIR}/tb_postgres.sql" ]; then
    echo "PostgreSQL备份文件存在并有效" | tee -a ${LOG_FILE}
else
    echo "PostgreSQL备份文件缺失或无效" | tee -a ${LOG_FILE}
fi

if [ -d "${EXTRACT_DIR}/cassandra" ]; then
    echo "Cassandra备份文件存在" | tee -a ${LOG_FILE}
else
    echo "Cassandra备份文件缺失" | tee -a ${LOG_FILE}
fi

if [ -f "${EXTRACT_DIR}/tb_config.tar.gz" ]; then
    echo "ThingsBoard配置备份存在" | tee -a ${LOG_FILE}
else
    echo "ThingsBoard配置备份缺失" | tee -a ${LOG_FILE}
fi

if [ -f "${EXTRACT_DIR}/tb_data.tar.gz" ]; then
    echo "ThingsBoard数据备份存在" | tee -a ${LOG_FILE}
else
    echo "ThingsBoard数据备份缺失" | tee -a ${LOG_FILE}
fi

# 清理临时目录
rm -rf ${TEMP_DIR}
echo "备份验证完成" | tee -a ${LOG_FILE}
EOF

# 创建tb_restore.sh
cat > ${SCRIPTS_DIR}/tb_restore.sh << 'EOF'
#!/bin/bash

# 检查参数
if [ $# -ne 1 ]; then
    echo "用法: $0 <备份文件路径>"
    exit 1
fi

BACKUP_FILE=$1
LOG_FILE="/var/log/tb_restore.log"

# 检查备份文件是否存在
if [ ! -f "${BACKUP_FILE}" ]; then
    echo "备份文件不存在: ${BACKUP_FILE}" | tee -a ${LOG_FILE}
    exit 1
fi

echo "开始ThingsBoard还原 - 使用备份: ${BACKUP_FILE}" | tee -a ${LOG_FILE}

# 创建临时目录
TEMP_DIR=$(mktemp -d)
tar -xzf ${BACKUP_FILE} -C ${TEMP_DIR}

# 获取备份日期
BACKUP_DATE=$(basename ${BACKUP_FILE} | sed 's/thingsboard_backup_//' | sed 's/.tar.gz//')
EXTRACT_DIR="${TEMP_DIR}/${BACKUP_DATE}"

# 1. 停止ThingsBoard服务
echo "停止ThingsBoard服务..." | tee -a ${LOG_FILE}
systemctl stop thingsboard
if [ $? -eq 0 ]; then echo "ThingsBoard服务已停止" | tee -a ${LOG_FILE}; else echo "无法停止ThingsBoard服务" | tee -a ${LOG_FILE}; fi

# 2. 还原PostgreSQL数据库
echo "还原PostgreSQL数据库..." | tee -a ${LOG_FILE}
# 首先删除现有数据库
sudo -u postgres psql -c "DROP DATABASE IF EXISTS thingsboard;"
sudo -u postgres psql -c "CREATE DATABASE thingsboard;"
# 还原数据
sudo -u postgres psql thingsboard < ${EXTRACT_DIR}/tb_postgres.sql
if [ $? -eq 0 ]; then echo "PostgreSQL还原成功" | tee -a ${LOG_FILE}; else echo "PostgreSQL还原失败" | tee -a ${LOG_FILE}; fi

# 3. 停止Cassandra服务
echo "停止Cassandra服务..." | tee -a ${LOG_FILE}
systemctl stop cassandra
if [ $? -eq 0 ]; then echo "Cassandra服务已停止" | tee -a ${LOG_FILE}; else echo "无法停止Cassandra服务" | tee -a ${LOG_FILE}; fi

# 4. 还原Cassandra数据
echo "还原Cassandra数据..." | tee -a ${LOG_FILE}

# 4.1 查找Cassandra数据目录
CASSANDRA_DATA_DIR=$(grep -r "data_file_directories" /etc/cassandra/cassandra.yaml | awk '{print $2}' | tr -d '[]" ')
if [ -z "$CASSANDRA_DATA_DIR" ]; then
    CASSANDRA_DATA_DIR="/var/lib/cassandra/data"
fi

# 4.2 备份现有Cassandra数据
mv ${CASSANDRA_DATA_DIR}/thingsboard ${CASSANDRA_DATA_DIR}/thingsboard.bak

# 4.3 创建新目录结构
mkdir -p ${CASSANDRA_DATA_DIR}/thingsboard

# 4.4 还原Cassandra数据
cp -r ${EXTRACT_DIR}/cassandra/* ${CASSANDRA_DATA_DIR}/thingsboard/
chown -R cassandra:cassandra ${CASSANDRA_DATA_DIR}/thingsboard
if [ $? -eq 0 ]; then echo "Cassandra数据还原成功" | tee -a ${LOG_FILE}; else echo "Cassandra数据还原失败" | tee -a ${LOG_FILE}; fi

# 5. 还原ThingsBoard配置
echo "还原ThingsBoard配置..." | tee -a ${LOG_FILE}
tar -xzf ${EXTRACT_DIR}/tb_config.tar.gz -C /
if [ $? -eq 0 ]; then echo "ThingsBoard配置还原成功" | tee -a ${LOG_FILE}; else echo "ThingsBoard配置还原失败" | tee -a ${LOG_FILE}; fi

# 6. 还原ThingsBoard数据
echo "还原ThingsBoard数据..." | tee -a ${LOG_FILE}
tar -xzf ${EXTRACT_DIR}/tb_data.tar.gz -C /
if [ $? -eq 0 ]; then echo "ThingsBoard数据还原成功" | tee -a ${LOG_FILE}; else echo "ThingsBoard数据还原失败" | tee -a ${LOG_FILE}; fi

# 7. 修复权限
echo "修复文件权限..." | tee -a ${LOG_FILE}
chown -R thingsboard:thingsboard /etc/thingsboard
chown -R thingsboard:thingsboard /var/lib/thingsboard
chmod -R 755 /etc/thingsboard
chmod -R 755 /var/lib/thingsboard

# 8. 启动服务
echo "启动服务..." | tee -a ${LOG_FILE}
systemctl start cassandra
if [ $? -eq 0 ]; then echo "Cassandra服务已启动" | tee -a ${LOG_FILE}; else echo "无法启动Cassandra服务" | tee -a ${LOG_FILE}; fi

# 等待Cassandra完全启动
echo "等待Cassandra启动..." | tee -a ${LOG_FILE}
sleep 60

systemctl start thingsboard
if [ $? -eq 0 ]; then echo "ThingsBoard服务已启动" | tee -a ${LOG_FILE}; else echo "无法启动ThingsBoard服务" | tee -a ${LOG_FILE}; fi

# 9. 清理
echo "清理临时文件..." | tee -a ${LOG_FILE}
rm -rf ${TEMP_DIR}
if [ -d "${CASSANDRA_DATA_DIR}/thingsboard.bak" ]; then
    echo "保留Cassandra旧数据备份于 ${CASSANDRA_DATA_DIR}/thingsboard.bak" | tee -a ${LOG_FILE}
    echo "确认系统正常运行后可手动删除" | tee -a ${LOG_FILE}
fi

echo "ThingsBoard还原完成" | tee -a ${LOG_FILE}
EOF

# 创建tb_remote_backup.sh
cat > ${SCRIPTS_DIR}/tb_remote_backup.sh << 'EOF'
#!/bin/bash

# 远程服务器信息 - 请修改为实际的远程服务器信息
REMOTE_SERVER="user@backup-server.example.com"
REMOTE_PATH="/path/to/backups"
LOG_FILE="/var/log/tb_remote_backup.log"

# 本地备份目录
LOCAL_BACKUP_DIR="/backup/thingsboard"

echo "开始同步备份到远程服务器 - $(date)" | tee -a ${LOG_FILE}

# 使用rsync同步备份文件
rsync -avz --delete ${LOCAL_BACKUP_DIR}/ ${REMOTE_SERVER}:${REMOTE_PATH}/
if [ $? -eq 0 ]; then
    echo "备份同步成功" | tee -a ${LOG_FILE}
else
    echo "备份同步失败" | tee -a ${LOG_FILE}
    # 发送失败通知邮件
    echo "ThingsBoard备份同步失败，请检查日志" | mail -s "ThingsBoard备份同步失败" admin@example.com
fi

echo "备份同步完成 - $(date)" | tee -a ${LOG_FILE}
EOF

# 创建备份监控脚本
cat > ${SCRIPTS_DIR}/tb_backup_monitor.sh << 'EOF'
#!/bin/bash

# 监控备份是否成功完成
# 如果24小时内没有新备份，发送警报

LOG_FILE="/var/log/tb_backup_monitor.log"
BACKUP_DIR="/backup/thingsboard"

# 查找最新备份文件
LATEST_BACKUP=$(find ${BACKUP_DIR} -name "thingsboard_backup_*" -type f -printf "%T@ %p\n" | sort -n | tail -1 | cut -d' ' -f2-)

if [ -z "$LATEST_BACKUP" ]; then
    echo "未找到备份文件" | tee -a ${LOG_FILE}
    echo "ThingsBoard备份监控：未找到任何备份文件" | mail -s "ThingsBoard备份警报" admin@example.com
    exit 1
fi

# 获取最新备份文件的时间戳
BACKUP_TIME=$(stat -c %Y "${LATEST_BACKUP}")
CURRENT_TIME=$(date +%s)
DIFF_HOURS=$(( (CURRENT_TIME - BACKUP_TIME) / 3600 ))

echo "最新备份: ${LATEST_BACKUP}, 距今: ${DIFF_HOURS}小时" | tee -a ${LOG_FILE}

# 如果超过24小时没有新备份，发送警报
if [ ${DIFF_HOURS} -gt 24 ]; then
    echo "ThingsBoard备份监控：超过24小时没有新备份" | mail -s "ThingsBoard备份警报" admin@example.com
fi

# 检查备份空间使用情况
BACKUP_SPACE=$(du -sh ${BACKUP_DIR} | cut -f1)
AVAILABLE_SPACE=$(df -h ${BACKUP_DIR} | awk 'NR==2 {print $4}')

echo "备份空间使用: ${BACKUP_SPACE}, 可用空间: ${AVAILABLE_SPACE}" | tee -a ${LOG_FILE}

# 如果可用空间小于20GB，发送警报
AVAILABLE_GB=$(df -BG ${BACKUP_DIR} | awk 'NR==2 {print $4}' | sed 's/G//')
if [ ${AVAILABLE_GB} -lt 20 ]; then
    echo "ThingsBoard备份监控：备份空间不足，仅剩 ${AVAILABLE_SPACE}" | mail -s "ThingsBoard备份空间警报" admin@example.com
fi
EOF

# 设置执行权限
chmod +x ${SCRIPTS_DIR}/*.sh

# 设置定时任务
echo "设置定时任务..."
(crontab -l 2>/dev/null; echo "0 2 * * * ${SCRIPTS_DIR}/tb_backup.sh") | crontab -
(crontab -l 2>/dev/null; echo "0 5 * * * ${SCRIPTS_DIR}/tb_remote_backup.sh") | crontab -
(crontab -l 2>/dev/null; echo "0 8 * * * ${SCRIPTS_DIR}/tb_backup_monitor.sh") | crontab -
(crontab -l 2>/dev/null; echo "0 9 * * 0 ${SCRIPTS_DIR}/tb_verify_backup.sh") | crontab -

# 创建符号链接到/usr/local/bin目录
ln -sf ${SCRIPTS_DIR}/tb_backup.sh /usr/local/bin/tb-backup
ln -sf ${SCRIPTS_DIR}/tb_restore.sh /usr/local/bin/tb-restore
ln -sf ${SCRIPTS_DIR}/tb_verify_backup.sh /usr/local/bin/tb-verify-backup

echo "创建日志文件..."
touch ${LOG_DIR}/tb_backup.log
touch ${LOG_DIR}/tb_backup_verify.log
touch ${LOG_DIR}/tb_restore.log
touch ${LOG_DIR}/tb_remote_backup.log
touch ${LOG_DIR}/tb_backup_monitor.log

chmod 644 ${LOG_DIR}/tb_*.log

echo "Thingsboard备份还原方案安装完成！"
echo ""
echo "可用命令:"
echo "  tb-backup          - 执行完整备份"
echo "  tb-restore         - 还原备份"
echo "  tb-verify-backup   - 验证最新备份"
echo ""
echo "备份文件位置: ${BACKUP_DIR}"
echo "脚本位置: ${SCRIPTS_DIR}"
echo "日志文件位置: ${LOG_DIR}/tb_*.log"
echo ""
echo "请确保更新 ${SCRIPTS_DIR}/tb_remote_backup.sh 中的远程服务器信息"
echo "还原命令示例: tb-restore /backup/thingsboard/thingsboard_backup_2023-04-01_02-00-00.tar.gz"
EOF 